import re
from rest_framework_jwt.settings import api_settings
from itsdangerous import TimedJSONWebSignatureSerializer as TJS

from users.models import User
from rest_framework import serializers
from django_redis import  get_redis_connection
from django.conf import settings
from celery_tasks.email.tasks import send_email


# 涉及到用户模型类使用ModelSerializer
class UserSerializers(serializers.ModelSerializer):

    #显示指明模型类中诶有的字段 只参与序列化验证write_only=True
    password2 = serializers.CharField(max_length=20,min_length=8,write_only=True)
    sms_code = serializers.CharField(max_length=6,min_length=6,write_only=True)
    allow = serializers.CharField(write_only=True)

    # 只进行序列化返回
    token = serializers.CharField(read_only=True)



    class Meta:
        model = User # 对那个模型类进行操作
        fields = ('username', 'password', 'password2', 'mobile', 'allow', 'sms_code', 'id','token')
        extra_kwargs = {
            # 添加指定属性
            'password':
                {
                    'max_length': 20,
                    'min_length': 8,
                    'write_only': True
                },
            'username':
                {
                    'max_length': 20,
                    'min_length': 5,
                }
        }

    # 验证手机号格式 单一验证
    def validate_mobile(self,value):
        if not re.match(r'^1[3-9]\d{9}$',value):
            raise serializers.ValidationError('手机号不匹配')

        return value

    # 验证选中状态
    def validate_allow(self, value):
        if value != 'true':
            raise serializers.ValidationError('协议未同意')

        return value

    # 验证两次密码和短信验证 多个字段验证
    def validate(self, attrs):
        # 密码判断
        if attrs['password'] != attrs['password2']:
            raise serializers.ValidationError('两次密码不一致')

        # 判断用户名是否是手机格式
        if re.match(r'^1[3-9]\d{9}$',attrs['username']):
            if attrs['username'] != attrs['mobile']:
                raise serializers.ValidationError('用户名和手机号不一致')


        # 1 短信验证 获取缓存中的短信验证码
        conn = get_redis_connection('sms_code')
        real_sms_code = conn.get('sms_code_%s' % attrs['mobile'])

        # 2 判断短信验证码是否失效
        if real_sms_code is None:
            raise serializers.ValidationError('短信验证码已失效')

        # 3 对比用户输入的短信验证码,redis获取的数据类型是bytes类型 需要转换
        if attrs['sms_code'] != real_sms_code.decode():
            raise serializers.ValidationError('输入短信验证码错误')
        return attrs


    # 保存 两种方法
    # validated_data :存储的所有数据

    def create(self, validated_data):

        # 删除不需要的信息
        """

        :param validated_data:
        :return:
        """
        del validated_data['password2']
        del validated_data['sms_code']
        del validated_data['allow']
        print(validated_data)


        # 将删除的数据进行保存
        # user = User.objects.create_user(validated_data)

        # 手动写入需要保存的信息,
        # create_user ：管理器方法，创建、保存并返回一个User对象 保存密文密码
        user = User.objects.create_user(username=validated_data['username'],password=validated_data['password'],
                                        mobile=validated_data['mobile'])

        # 不会对密码加密
        # User.objects.create()

        # 生成jwt token 在注册成功返回时 携带token 加密返回

        jwt_payload_handler = api_settings.JWT_PAYLOAD_HANDLER
        jwt_encode_handler = api_settings.JWT_ENCODE_HANDLER

        payload = jwt_payload_handler(user)
        token = jwt_encode_handler(payload)

        # 给user对象添加属性返回给前端
        user.token=token
        return user

class UserShowSerializers(serializers.ModelSerializer):
    class Meta:
        model = User
        fields = ('username','mobile','email','id','email_active')

class UserEmailSerializers(serializers.Serializer):

    # 对传入的字段自动进行格式验证
    email = serializers.CharField()

    def update(self, instance, validated_data):

        #加密用户数据
        tjs = TJS(settings.SECRET_KEY,300)
        # instance
        token = tjs.dumps({'username': instance.username}).decode()
        # # 收件人
        to_email = validated_data['email']


        # # 异步发送邮件
        send_email.delay(token,to_email)

        instance.email = validated_data['email']
        instance.save()
        return instance
